package com.shanzmoo.h5.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.shanzmoo.core.exception.MallMemberException;
import com.shanzmoo.core.manager.JwtManager;
import com.shanzmoo.core.service.IAliSmsService;
import com.shanzmoo.core.util.RedisCoreKeyUtils;
import com.shanzmoo.db.personnel.entity.MemberInfoEntity;
import com.shanzmoo.db.personnel.service.IMemberInfoService;
import com.shanzmoo.h5.domain.AuthUser;
import com.shanzmoo.h5.domain.bo.MemberTokenBO;
import com.shanzmoo.h5.service.ILoginService;
import com.shanzmoo.base.bean.SResponse;
import com.shanzmoo.base.constant.Constant;
import com.shanzmoo.base.constant.MemberType;
import com.shanzmoo.base.constant.RegularExpression;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * 登录服务
 *
 * @author: Gzhao 2020/12/20
 */
@Slf4j
@Service
public class LoginServiceImpl implements ILoginService {

    @Value("${jwt.tokenHead}")
    private String tokenHead;
    @Autowired
    private IMemberInfoService memberInfoService;
    @Autowired
    private IAliSmsService aliSmsService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtManager jwtManager;

    @Override
    public SResponse<Boolean> sendIdentifyingCode(String phone) {
        // 1. 校验手机号
        if (!ReUtil.isMatch(RegularExpression.MOBILE_1, phone)){
            return SResponse.fail(Constant.ERRCODE_LOGIC, "请输入正确的手机号");
        }

        // 2. 判断手机号是否已经注册
        MemberInfoEntity memberInfo = memberInfoService.getOne(
                new QueryWrapper<MemberInfoEntity>()
                        .eq("mobile", phone)
        );

        boolean register = false;
        // 3. 若用户未注册，则先在系统中注册用户
        if (memberInfo == null){

            memberInfo = new MemberInfoEntity();
            memberInfo.setMobile(phone);
            memberInfo.setType(MemberType.NORMAL);
            memberInfo.setStatus(false);
            memberInfo.setName(phone);
            memberInfoService.save(memberInfo);

            register = true;
        }

        // 4. 向用户发送验证码
        String identifyingCode = RandomUtil.randomNumbers(6);
        log.info("用户id：{}，手机号：{}，生成短信验证码：{}", memberInfo.getId(), memberInfo.getMobile(), identifyingCode);

        stringRedisTemplate.opsForList().leftPush(RedisCoreKeyUtils.installIdentifyingCodeKey(memberInfo.getId()), identifyingCode);
        stringRedisTemplate.expire(RedisCoreKeyUtils.installIdentifyingCodeKey(memberInfo.getId()), Constant.CODE_EXPIRE, TimeUnit.SECONDS);

        if (register){
            aliSmsService.sendRegisterSms(phone, identifyingCode);
        } else {
            aliSmsService.sendLoginSms(phone, identifyingCode);
        }

        return SResponse.ok(Boolean.TRUE);
    }

    @Override
    public SResponse<MemberTokenBO> loginByPhone(String phone, String code) {
        MemberInfoEntity memberInfo = memberInfoService.getOne(
                new QueryWrapper<MemberInfoEntity>()
                        .eq("mobile", phone)
        );
        if (memberInfo == null){
            return SResponse.fail(Constant.ERRCODE_LOGIC, "请输入正确的手机号");
        }

        if (!Arrays.asList("15527850620").contains(phone)){

            String value = stringRedisTemplate.opsForList().leftPop(RedisCoreKeyUtils.installIdentifyingCodeKey(memberInfo.getId()));

            if (StrUtil.isBlank(value) || !value.equals(code)){
                return SResponse.fail(Constant.ERRCODE_LOGIC, "请输入正确的验证码");
            }

        }

        try {
            String token = obtainToken(memberInfo.getMobile());
            MemberTokenBO memberTokenBO = new MemberTokenBO(token, tokenHead + " ", null, memberInfo.getOpenId());

            // 将token存入到redis
            String memberTokenKey = RedisCoreKeyUtils.installMemberTokenKey();
            stringRedisTemplate.opsForHash().put(memberTokenKey, String.valueOf(memberInfo.getId()), memberTokenBO.toString());

            return SResponse.ok(memberTokenBO);
        } catch (Exception e) {

            log.error("根据用手机号:{}登陆异常:{}", phone, e);
            throw new MallMemberException("手机号登录失败");
        }
    }

    private String obtainToken(String mobile) {
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(mobile, Constant.MALL_PASSWORD));

        SecurityContextHolder.getContext().setAuthentication(authentication);

        AuthUser authUser = JSON.parseObject(JSON.toJSONString(authentication.getPrincipal()), AuthUser.class);
        return jwtManager. createJWT(false, authUser.getUserId(), authUser.getUsername(),
                authUser.getRoleIds(), authUser.getAuthorities());
    }

}
